package com.varton.v3;

import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * 产生代理类
 */
public class ProxyProducer {

    private final static String RN = "\r\n";

    /**
     * 产生代理类实例
     * @return
     */
    public static Object getInstance(MyClassLoader classLoader, Class<?> interfas, MyInvocationHandler handler) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //产生源码
        String src = produceSrc(interfas,handler);
        //将源码写到硬盘
        writeClassTodisk(src);
        //编译.java文件
        compileClass();
        //加载类
        Class<?> clazz = classLoader.findClass("com.varton.v3.$Proxy");
        Constructor<?> c = clazz.getConstructor(handler.getClass());
        return c.newInstance(handler);
    }

    /**
     * 产生代理类源代码
     * @return
     */
    public static String produceSrc(Class<?> interfas, MyInvocationHandler handler){
        StringBuilder strBder = new StringBuilder();
        strBder.append("package com.varton.v3;"+RN);
        strBder.append("public class $Proxy implements "+ interfas.getName() +"{"+RN);
        strBder.append("private "+ handler.getClass().getName() +" handler;"+RN);
        strBder.append("public $Proxy("+handler.getClass().getName()+" handler){"+RN);
        strBder.append("this.handler = handler;"+RN);
        strBder.append("}"+RN);
        for (Method m:interfas.getMethods()){
            strBder.append("public "+m.getReturnType().getName()+" "+m.getName()+"() throws NoSuchMethodException {"+RN);
            strBder.append(Method.class.getName() +" md = "+interfas.getName()+".class.getMethod(\""+m.getName()+"\");"+RN);
            strBder.append("handler.invoke(this, md, null);"+RN);
            strBder.append("}"+RN);
        }
        strBder.append("}");
        return strBder.toString();
    }

    /**
     * 将源码写到硬盘上
     * @param src
     */
    public static void writeClassTodisk(String src){
        String prefix = ProxyProducer.class.getResource("").getPath();
        String filePath = prefix+"$Proxy.java";
        File f = new File(filePath);
        try {
            FileWriter fw = new FileWriter(f);
            fw.write(src);
            fw.flush();
            fw.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 编译.java文件
     */
    public static void compileClass(){
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        String prefix = ProxyProducer.class.getResource("").getPath();
        String filePath = prefix+"$Proxy.java";
        File f = new File(filePath);
        StandardJavaFileManager fileManger = compiler.getStandardFileManager(null,null,null);
        Iterable<? extends JavaFileObject> until = fileManger.getJavaFileObjects(f);
        JavaCompiler.CompilationTask task = compiler.getTask(null,fileManger,null,null,null,until);
        task.call();
        f.delete();//删除.java文件
    }

}
